package com.suke.czx.common.utils;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 应用模块名称: 工具类
 * 代码描述: 阿里云OSS工具类
 * copyright: AUZAR ALL RIGHTS RESERVED
 * company: AUZAR
 *
 * @author: 颜米晨
 * @date: 2021/09/07 14:52:18
 */
@Slf4j
@Component
public class OssUtil {

    /**
     * OSS客户端
     */
    private static OSSClient ossCli;

    /**
     * 桶名
     */
    private static String bucket;

    /**
     * 路径
     */
    private static String path;

    @Resource
    private OSSClient ossClient;

    @Value("${oss.bucket}")
    public String tempBucket;

    @Value("${oss.path}")
    public String tempPath;

    /**
     * 初始化
     */
    @PostConstruct
    public void init() {
        ossCli = ossClient;
        bucket = tempBucket;
        path = tempPath;
    }

    /**
     * 上传文件至OSS
     * @param is InputStream 文件输入流
     * @param fileName 文件名
     * @return 出错返回空字符串 成功返回新文件名
     */
    public static String uploadFile2Oss(InputStream is, String diskName, String fileName) {
        String newFileName = StrUtil.toString(UUID.randomUUID()).replace(Constant.HYPHEN, Constant.BLANK) + fileName;
        try {
            uploadFile2Oss(is, bucket, diskName, newFileName);
            return newFileName;
        } catch (Exception e) {
            throw new RuntimeException("文件上传失败");
        }
    }

    /**
     * 根据处理后的文件名称生成
     * @param is 文件输入流
     * @param bucketName 桶名
     * @param pathName 路径名
     * @param fileName 文件名称
     */
    public static void uploadFile2Oss(InputStream is, String bucketName, String pathName, String fileName) {
        try {
            //创建上传Object的Metadata
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(is.available());
            //设置无缓存
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setHeader("Pragma", "no-cache");
            objectMetadata.setContentType(FileUtil.getContentType(fileName.substring(fileName.lastIndexOf("."))));
            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            //上传文件
            PutObjectResult putResult = ossCli.putObject(bucketName, pathName + fileName, is, objectMetadata);
            putResult.getETag();
        } catch (Exception e) {
            log.error("uploadFile2OSS error", e);
            throw new RuntimeException("上传文件失败！");
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取上传文件存储URL
     * @param fileName 文件名称
     * @param bucketName 存储空间
     * @param pathName 路径名
     * @param expiration 过期时限
     * @return OSS Url
     */
    public static String getFileOssUrl(String fileName, String bucketName, String pathName, Long expiration) {
        // 设置文件url保存期限
        Date deadLine = new Date(System.currentTimeMillis() + expiration);
        // 生成URL
        URL url = ossCli.generatePresignedUrl(bucketName,pathName + fileName, deadLine);
        if (url != null) {
            return StrUtil.subBefore(StrUtil.toString(url), Constant.QUESTION_MARK, false);
        }
        return null;
    }

    /**
     * 获取上传文件存储URL
     * @param fileName 文件名称
     * @param pathName 路径名
     * @param expiration 过期时限
     * @return OSS Url
     */
    public static String getFileOssUrl(String fileName, String pathName, Long expiration) {
        return getFileOssUrl(fileName, bucket, pathName, expiration);
    }

    /**
     * 列举指定目录下的所有文件
     * @param bucketName 存储空间
     * @param diskName 存储目录
     * @return 文件名称数据集
     */
    public static List<String> getFileList(String bucketName, String diskName){
        //构造ListObjectsRequest请求
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);
        //设置prefix参数来获取fun目录下的所有文件
        listObjectsRequest.setPrefix( diskName + File.separator);
        //递归列出fun目录下的所有文件
        ObjectListing listing = ossCli.listObjects(listObjectsRequest);
        List<String> fileList = new ArrayList<>();
        for (OSSObjectSummary objectSummary : listing.getObjectSummaries()){
            fileList.add(objectSummary.getKey());
        }
        return fileList;
    }

    /**
     * 列举指定目录下的所有文件
     * @param diskName 存储目录
     * @return 文件名称数据集
     */
    public static List<String> getFileList(String diskName){
        return getFileList(bucket, diskName);
    }

    /**
     * 根据文件路径下载文件
     * @param bucketName 存储空间
     * @param diskName 目录名称
     * @param fileName 文件名称
     * @return InputStream 输入流
     */
    public static InputStream downloadFile(String bucketName, String diskName, String fileName){
        OSSObject ossObject = ossCli.getObject(bucketName, diskName + File.separator + fileName);
        return ossObject.getObjectContent();
    }

    /**
     * 根据文件全名（目录名 + 文件名）下载文件
     * @param bucketName 存储空间
     * @param objectName 文件全名
     * @return InputStream 输入流
     */
    public static InputStream downloadFile(String bucketName, String objectName){
        OSSObject ossObject = ossCli.getObject(bucketName, objectName);
        return ossObject.getObjectContent();
    }

    /**
     * 根据文件全名（目录名 + 文件名）下载文件
     * @param bucketName 存储空间
     * @param objectName 文件全名
     * @param filePath 文件路径
     */
    public static void downloadFile2Local(String bucketName, String objectName, String filePath){
        // 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖，不存在则新建。
        ossCli.getObject(new GetObjectRequest(bucketName, objectName), new File(filePath));
    }

    /**
     * 根据文件全名（目录名 + 文件名）下载文件
     * @param objectName 文件全名
     * @param filePath 文件路径
     */
    public static void downloadFile2Local(String objectName, String filePath){
        downloadFile2Local(bucket, objectName, filePath);
    }

    /**
     * 执行文件上传
     * @param is 输入流
     * @param fileName 文件名
     * @return 阿里云地址
     */
    public static String executeFileUpload(InputStream is, String fileName) {
        // 入参判断
        if (is == null || StrUtil.isBlank(fileName)) {
            throw new RuntimeException("上传文件不存在");
        }
        String newFileName = uploadFile2Oss(is, path, fileName);
        String url = getFileOssUrl(newFileName, bucket, path, 3600L);
        log.info("[aliyun Oss Response]: URL {}", url);
        // 返回结果
        return url;
    }

    /**
     * 执行临时文件上传
     * @param is 输入流
     * @param fileName 文件名
     * @return 阿里云地址
     */
    public static String tempExportFile(InputStream is, String fileName) {
        // 返回结果
        return executeFileUpload(is, fileName);
    }

}
